package Graphics;

import javax.swing.JFrame;

import java.awt.BorderLayout;
import java.awt.Graphics2D;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;

import javax.imageio.ImageIO;
import javax.media.opengl.*;
import javax.media.opengl.awt.GLCanvas;
import javax.media.opengl.glu.GLU;
import javax.media.opengl.glu.GLUquadric;

import com.jogamp.opengl.util.*;
import com.jogamp.opengl.util.texture.Texture;
import com.jogamp.opengl.util.texture.TextureData;
import com.jogamp.opengl.util.texture.TextureIO;

public class SimpleScene extends GLCanvas implements GLEventListener {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private GLU m_glu;
	private FPSAnimator m_animator;
	private Texture m_earthTexture;
	private BufferedImage m_BufferedImage;
	private int m_BIw;
	private int m_BIh;

    public static void main(String[] args) {
        GLCapabilities capabilities = createGLCapabilities();
        SimpleScene canvas = new SimpleScene(capabilities, 1280, 720);
        JFrame frame = new JFrame("Mini JOGL Demo");
        frame.getContentPane().add(canvas, BorderLayout.CENTER);
        frame.setSize(1280, 720);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
        canvas.requestFocus();
    }
    
    public SimpleScene(GLCapabilities capabilities, int width, int height) {
        addGLEventListener(this);
    }
    
    private static GLCapabilities createGLCapabilities() {
    	GLProfile glp = GLProfile.getDefault();
        GLCapabilities capabilities = new GLCapabilities(glp);
        capabilities.setRedBits(8);
        capabilities.setBlueBits(8);
        capabilities.setGreenBits(8);
        capabilities.setAlphaBits(8);
        return capabilities;
    }

    @Override
    public void display(GLAutoDrawable drawable) {
    	
        update();
        render(drawable);
    }

    @Override
    public void dispose(GLAutoDrawable drawable) {
    }

    @Override
    public void init(GLAutoDrawable drawable) {
    	GL2 gl = drawable.getGL().getGL2();
        drawable.setGL(new DebugGL2(gl));

        // Global settings.
        
        gl.glEnable(GL2.GL_DEPTH_TEST);
        // Fixed this. Had to use GL_GEQUAL to get mine to work, because
        // I was missing GL_DEPTH_BUFFER_BIT during the clear operation
        // in display()! Now it works as intended.
        gl.glDepthFunc(GL2.GL_LEQUAL);
        gl.glShadeModel(GL2.GL_SMOOTH);
        gl.glHint(GL2.GL_PERSPECTIVE_CORRECTION_HINT, GL2.GL_NICEST);
        gl.glClearColor(0.1f, 0.1f, 0.4f, 1f);

        m_glu = new GLU();
        
		////////////////////////
		// load earth image
		////////////////////////
		try {
			InputStream stream = getClass().getResourceAsStream("earthmap1k.jpg");
			TextureData data = TextureIO.newTextureData(GLProfile.getDefault(), stream,  false,  "jpg");
			m_earthTexture = TextureIO.newTexture(data);
		}
		catch(IOException exc) {
			exc.printStackTrace();
			System.exit(1);
		}
        
		////////////////////////
		// Buffered image
		////////////////////////
		m_BufferedImage = null;
		m_BIw = 0;
		m_BIh = 0;
		
		try {
			m_BufferedImage = ImageIO.read(getClass().getResource("test.jpg"));
			m_BIw = m_BufferedImage.getWidth();
			m_BIh = m_BufferedImage.getHeight();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
        m_animator = new FPSAnimator(this, 60);
        m_animator.start();
        
        
        
        
    }

    @Override
    public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
    	GL2 gl = drawable.getGL().getGL2();
        gl.glViewport(0, 0, width, height);
    }

    private void update() {
    	
    }

    private void render(GLAutoDrawable drawable) {
        GL2 gl = drawable.getGL().getGL2();

        // fixed this to also clear the depth buffer.
        gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);

        setCamera(gl, m_glu, 30);
            	
        //////////////////////////////
    	// Write triangle.
        //////////////////////////////
        /*gl.glColor3f(0.9f, 0.5f, 0.2f);
        gl.glBegin(GL.GL_TRIANGLE_FAN);
        gl.glVertex3f(+20, -20, 0);
        gl.glVertex3f(-20, -20, 0);
        
        gl.glVertex3f(0, 20, 0);
        gl.glEnd();*/
        
        //////////////////////////////
        // Draw sphere (possible styles: FILL, LINE, POINT).
        //////////////////////////////
        /*gl.glColor3f(0.3f, 0.5f, 1f);
        GLUquadric earth = m_glu.gluNewQuadric();
        m_glu.gluQuadricDrawStyle(earth, GLU.GLU_FILL);
        m_glu.gluQuadricNormals(earth, GLU.GLU_FLAT);
        m_glu.gluQuadricOrientation(earth, GLU.GLU_OUTSIDE);
        final float radius = 6.378f;
        final int slices = 16;
        final int stacks = 16;
        m_glu.gluSphere(earth, radius, slices, stacks);
        m_glu.gluDeleteQuadric(earth);*/
        
        ////////////////////////////////
        // Draw a lit sphere
        ////////////////////////////////
        
        gl.glEnable(GL2.GL_DEPTH_TEST);
        gl.glDepthFunc(GL2.GL_LEQUAL);
        gl.glShadeModel(GL2.GL_SMOOTH);
        gl.glHint(GL2.GL_PERSPECTIVE_CORRECTION_HINT, GL2.GL_NICEST);
        gl.glDisable(GL2.GL_TEXTURE_2D);
        
        // Prepare light parameters.
        float SHINE_ALL_DIRECTIONS = 1;
        float[] lightPos = {-30, 0, 0, SHINE_ALL_DIRECTIONS};
        float[] lightColorAmbient = {0.2f, 0.2f, 0.2f, 1f};
        float[] lightColorSpecular = {0.8f, 0.8f, 0.8f, 1f};

        // Set light parameters.
        gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_POSITION, lightPos, 0);
        gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_AMBIENT, lightColorAmbient, 0);
        gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_SPECULAR, lightColorSpecular, 0);

        // Enable lighting in GL.
        gl.glEnable(GL2.GL_LIGHT1);
        gl.glEnable(GL2.GL_LIGHTING);

        // Set material properties.
        float[] rgba = {1f, 1f, 1f};
        gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_AMBIENT, rgba, 0);
        gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_SPECULAR, rgba, 0);
        gl.glMaterialf(GL2.GL_FRONT, GL2.GL_SHININESS, 0.5f);
        
        // set the texture
        m_earthTexture.enable(gl);
        m_earthTexture.bind(gl);
        
        // draw the sphere
        //gl.glColor3f(0.3f, 0.5f, 1f);
        GLUquadric earth = m_glu.gluNewQuadric();
        m_glu.gluQuadricTexture(earth, true);
        m_glu.gluQuadricDrawStyle(earth, GLU.GLU_FILL);
        m_glu.gluQuadricNormals(earth, GLU.GLU_FLAT);
        m_glu.gluQuadricOrientation(earth, GLU.GLU_OUTSIDE);
        final float radius = 6.378f;
        final int slices = 16;
        final int stacks = 16;
        m_glu.gluSphere(earth, radius, slices, stacks);
        m_glu.gluDeleteQuadric(earth);        
        
        // Draw texture
        
        gl.glMatrixMode(GL2.GL_PROJECTION); 
        gl.glLoadIdentity();
        gl.glOrtho(0, m_BufferedImage.getWidth(), m_BufferedImage.getHeight(), 0, 0, 1); 
        
        gl.glMatrixMode(GL2.GL_MODELVIEW); 
        gl.glDisable(GL2.GL_DEPTH_TEST);      
        //gl.glClearColor(1.0f, 1.0f, 1.0f, 0.0f); 
        //gl.glClear(GL2.GL_COLOR_BUFFER_BIT); 
        gl.glBlendFunc (GL2.GL_SRC_ALPHA, GL2.GL_ONE_MINUS_SRC_ALPHA); 
        
        gl.glEnable (GL2.GL_BLEND); 
        
        WritableRaster raster = Raster.createInterleavedRaster (DataBuffer.TYPE_BYTE, m_BIw, m_BIh,	4, null);
        ComponentColorModel colorModel=	new ComponentColorModel (ColorSpace.getInstance(ColorSpace.CS_sRGB),
						new int[] {8,8,8,8},
						true,
						false,
						ComponentColorModel.TRANSLUCENT,
						DataBuffer.TYPE_BYTE);
			BufferedImage dukeImg = new BufferedImage (colorModel, raster, false, null);
 			Graphics2D g = dukeImg.createGraphics();
			g.drawImage(m_BufferedImage, null, null);
			DataBufferByte dukeBuf = (DataBufferByte)raster.getDataBuffer();
			byte[] dukeRGBA = dukeBuf.getData();
			ByteBuffer bb = ByteBuffer.wrap(dukeRGBA);
			bb.position(0);
			bb.mark();
			gl.glBindTexture(GL2.GL_TEXTURE_2D, 13);
			gl.glPixelStorei(GL2.GL_UNPACK_ALIGNMENT, 1);
			gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_S, GL2.GL_CLAMP);
			gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_T, GL2.GL_CLAMP);
			gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_LINEAR);
			gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_LINEAR);
			gl.glTexEnvf(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL2.GL_REPLACE);
			gl.glTexImage2D (GL2.GL_TEXTURE_2D, 0, GL2.GL_RGBA, m_BIw, m_BIh, 0, GL2.GL_RGBA, GL2.GL_UNSIGNED_BYTE, bb);
 
			int left = 10;
			int top = 100;
			gl.glEnable(GL2.GL_TEXTURE_2D);
			gl.glBindTexture (GL2.GL_TEXTURE_2D, 13);
			gl.glBegin (GL2.GL_POLYGON);
			gl.glTexCoord2d (0, 0);
			gl.glVertex2d (left,top);
			gl.glTexCoord2d(1,0);
			gl.glVertex2d (left + m_BIw, top);
			gl.glTexCoord2d(1,1);
			gl.glVertex2d (left + m_BIw, top + m_BIh);
			gl.glTexCoord2d(0,1);
			gl.glVertex2d (left, top + m_BIh);
			gl.glEnd ();	
			//gl.glFlush();
        
        
        
        
        
    }
    
    /**
     * Sets the camera for this iteration
     */
    private void setCamera(GL2 gl, GLU glu, float distance) {
    	// Change to projection matrix.
        gl.glMatrixMode(GL2.GL_PROJECTION);
        gl.glLoadIdentity();

        // Perspective.
        float widthHeightRatio = (float) getWidth() / (float) getHeight();
        glu.gluPerspective(45, widthHeightRatio, 1, 1000);
        glu.gluLookAt(0, 0, distance, 0, 0, 0, 0, 1, 0);

        // Change back to model view matrix.
        gl.glMatrixMode(GL2.GL_MODELVIEW);
        gl.glLoadIdentity();
    }
}